/**
	Pulsar engine. Additional include file.
	Delegates.

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.
		
	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/


#define PL_BIND_FF(fp)		pl::makeProxy(fp).bind<fp>()
#define PL_BIND_MF(fp, ip)	pl::makeProxy(fp).bind<fp>(ip)

namespace pl
{

template <typename Signature> class Function;

/// 0 args ---
template <typename R> struct FreeFunctionProxy0
{
	typedef R (*FPtr)();
	typedef Function<R ()> Func;

	template <FPtr fp>
	static Func bind()
	{
		return Func(&FreeFunctionProxy0::template wrapper<fp>, 0);
	}

private:
	template <FPtr fp>
	static R wrapper(const void*)
	{
		return fp();
	}
};

///
template <typename R, typename C> struct MemberFunctionProxy0
{
	typedef R (C::* const FPtr)();
	typedef Function<R ()> Func;

	template <FPtr fp>
	static Func bind(C* ip)
	{
		return Func(&MemberFunctionProxy0::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip)
	{
		C* instance = const_cast<C*>(static_cast<const C*>(ip));
		return (instance->*fp)();
	}
};

///
template <typename R, typename C> struct ConstMemberFunctionProxy0
{
	typedef R (C::* const FPtr)() const;
	typedef Function<R ()> Func;

	template <FPtr fp>
	static Func bind(const C* ip)
	{
		return Func(&ConstMemberFunctionProxy0::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip)
	{
		const C* instance = static_cast<const C*>(ip);
		return (instance->*fp)();
	}
};

///
template <typename R> FreeFunctionProxy0<R> makeProxy(R (*fp)())
{
	return FreeFunctionProxy0<R>();
}

///
template <typename R, typename C> MemberFunctionProxy0<R, C> makeProxy(R (C::* const fp)())
{
	return MemberFunctionProxy0<R, C>();
}

///
template <typename R, typename C> ConstMemberFunctionProxy0<R, C> makeProxy(R (C::* const fp)() const)
{
	return ConstMemberFunctionProxy0<R, C>();
}

/// 1 args ---

///
template <typename R, typename A0> struct FreeFunctionProxy1
{
	typedef R (*FPtr)(A0);
	typedef Function<R (A0)> Func;

	template <FPtr fp>
	static Func bind()
	{
		return Func(&FreeFunctionProxy1::template wrapper<fp>, 0);
	}

private:
	template <FPtr fp>
	static R wrapper(const void*, A0 a0)
	{
		return fp(a0);
	}
};

///
template <typename R, typename C, typename A0> struct MemberFunctionProxy1
{
	typedef R (C::* const FPtr)(A0);
	typedef Function<R (A0)> Func;

	template <FPtr fp>
	static Func bind(C* ip)
	{
		return Func(&MemberFunctionProxy1::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0)
	{
		C* instance = const_cast<C*>(static_cast<const C*>(ip));
		return (instance->*fp)(a0);
	}
};

///
template <typename R, typename C, typename A0> struct ConstMemberFunctionProxy1
{
	typedef R (C::* const FPtr)(A0) const;
	typedef Function<R (A0)> Func;

	template <FPtr fp>
	static Func bind(const C* ip)
	{
		return Func(&ConstMemberFunctionProxy1::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0)
	{
		const C* instance = static_cast<const C*>(ip);
		return (instance->*fp)(a0);
	}
};

///
template <typename R, typename A0> FreeFunctionProxy1<R, A0> makeProxy(R (*fp)(A0))
{
	return FreeFunctionProxy1<R, A0>();
}

///
template <typename R, typename C, typename A0> MemberFunctionProxy1<R, C, A0> makeProxy(R (C::* const fp)(A0))
{
	return MemberFunctionProxy1<R, C, A0>();
}

///
template <typename R, typename C, typename A0> ConstMemberFunctionProxy1<R, C, A0> makeProxy(R (C::* const fp)(A0) const)
{
	return ConstMemberFunctionProxy1<R, C, A0>();
}

/// 2 args ---
template <typename R, typename A0, typename A1> struct FreeFunctionProxy2
{
	typedef R (*FPtr)(A0, A1);
	typedef Function<R (A0, A1)> Func;

	template <FPtr fp>
	static Func bind()
	{
		return Func(&FreeFunctionProxy2::template wrapper<fp>, 0);
	}

private:
	template <FPtr fp>
	static R wrapper(const void*, A0 a0, A1 a1)
	{
		return fp(a0, a1);
	}
};

///
template <typename R, typename C, typename A0, typename A1> struct MemberFunctionProxy2
{
	typedef R (C::* const FPtr)(A0, A1);
	typedef Function<R (A0, A1)> Func;

	template <FPtr fp>
	static Func bind(C* ip)
	{
		return Func(&MemberFunctionProxy2::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1)
	{
		C* instance = const_cast<C*>(static_cast<const C*>(ip));
		return (instance->*fp)(a0, a1);
	}
};

///
template <typename R, typename C, typename A0, typename A1> struct ConstMemberFunctionProxy2
{
	typedef R (C::* const FPtr)(A0, A1) const;
	typedef Function<R (A0, A1)> Func;

	template <FPtr fp>
	static Func bind(const C* ip)
	{
		return Func(&ConstMemberFunctionProxy2::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1)
	{
		const C* instance = static_cast<const C*>(ip);
		return (instance->*fp)(a0, a1);
	}
};

///
template <typename R, typename A0, typename A1> FreeFunctionProxy2<R, A0, A1> makeProxy(R (*fp)(A0, A1))
{
	return FreeFunctionProxy2<R, A0, A1>();
}

///
template <typename R, typename C, typename A0, typename A1> MemberFunctionProxy2<R, C, A0, A1> makeProxy(R (C::* const fp)(A0, A1))
{
	return MemberFunctionProxy2<R, C, A0, A1>();
}

///
template <typename R, typename C, typename A0, typename A1> ConstMemberFunctionProxy2<R, C, A0, A1> makeProxy(R (C::* const fp)(A0, A1) const)
{
	return ConstMemberFunctionProxy2<R, C, A0, A1>();
}

/// 3 args ---

///
template <typename R, typename A0, typename A1, typename A2> struct FreeFunctionProxy3
{
	typedef R (*FPtr)(A0, A1, A2);
	typedef Function<R (A0, A1, A2)> Func;

	template <FPtr fp>
	static Func bind()
	{
		return Func(&FreeFunctionProxy3::template wrapper<fp>, 0);
	}

private:
	template <FPtr fp>
	static R wrapper(const void*, A0 a0, A1 a1, A2 a2)
	{
		return fp(a0, a1, a2);
	}
};

///
template <typename R, typename C, typename A0, typename A1, typename A2> struct MemberFunctionProxy3
{
	typedef R (C::* const FPtr)(A0, A1, A2);
	typedef Function<R (A0, A1, A2)> Func;

	template <FPtr fp>
	static Func bind(C* ip)
	{
		return Func(&MemberFunctionProxy3::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1, A2 a2)
	{
		C* instance = const_cast<C*>(static_cast<const C*>(ip));
		return (instance->*fp)(a0, a1, a2);
	}
};

///
template <typename R, typename C, typename A0, typename A1, typename A2> struct ConstMemberFunctionProxy3
{
	typedef R (C::* const FPtr)(A0, A1, A2) const;
	typedef Function<R (A0, A1, A2)> Func;

	template <FPtr fp>
	static Func bind(const C* ip)
	{
		return Func(&ConstMemberFunctionProxy3::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1, A2 a2)
	{
		const C* instance = static_cast<const C*>(ip);
		return (instance->*fp)(a0, a1, a2);
	}
};

///
template <typename R, typename A0, typename A1, typename A2> FreeFunctionProxy3<R, A0, A1, A2> makeProxy(R (*fp)(A0, A1, A2))
{
	return FreeFunctionProxy3<R, A0, A1, A2>();
}

///
template <typename R, typename C, typename A0, typename A1, typename A2> MemberFunctionProxy3<R, C, A0, A1, A2> makeProxy(R (C::* const fp)(A0, A1, A2))
{
	return MemberFunctionProxy3<R, C, A0, A1, A2>();
}

///
template <typename R, typename C, typename A0, typename A1, typename A2> ConstMemberFunctionProxy3<R, C, A0, A1, A2> makeProxy(R (C::* const fp)(A0, A1, A2) const)
{
	return ConstMemberFunctionProxy3<R, C, A0, A1, A2>();
}

/// 4 args ---
///
template <typename R, typename A0, typename A1, typename A2, typename A3> struct FreeFunctionProxy4
{
	typedef R (*FPtr)(A0, A1, A2, A3);
	typedef Function<R (A0, A1, A2, A3)> Func;

	template <FPtr fp>
	static Func bind()
	{
		return Func(&FreeFunctionProxy4::template wrapper<fp>, 0);
	}

private:
	template <FPtr fp>
	static R wrapper(const void*, A0 a0, A1 a1, A2 a2, A3 a3)
	{
		return fp(a0, a1, a2, a3);
	}
};

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3> struct MemberFunctionProxy4
{
	typedef R (C::* const FPtr)(A0, A1, A2, A3);
	typedef Function<R (A0, A1, A2, A3)> Func;

	template <FPtr fp>
	static Func bind(C* ip)
	{
		return Func(&MemberFunctionProxy4::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1, A2 a2, A3 a3)
	{
		C* instance = const_cast<C*>(static_cast<const C*>(ip));
		return (instance->*fp)(a0, a1, a2, a3);
	}
};

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3> struct ConstMemberFunctionProxy4
{
	typedef R (C::* const FPtr)(A0, A1, A2, A3) const;
	typedef Function<R (A0, A1, A2, A3)> Func;

	template <FPtr fp>
	static Func bind(const C* ip)
	{
		return Func(&ConstMemberFunctionProxy4::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1, A2 a2, A3 a3)
	{
		const C* instance = static_cast<const C*>(ip);
		return (instance->*fp)(a0, a1, a2, a3);
	}
};

///
template <typename R, typename A0, typename A1, typename A2, typename A3> FreeFunctionProxy4<R, A0, A1, A2, A3> makeProxy(R (*fp)(A0, A1, A2, A3))
{
	return FreeFunctionProxy4<R, A0, A1, A2, A3>();
}

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3> MemberFunctionProxy4<R, C, A0, A1, A2, A3> makeProxy(R (C::* const fp)(A0, A1, A2, A3))
{
	return MemberFunctionProxy4<R, C, A0, A1, A2, A3>();
}

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3> ConstMemberFunctionProxy4<R, C, A0, A1, A2, A3> makeProxy(R (C::* const fp)(A0, A1, A2, A3) const)
{
	return ConstMemberFunctionProxy4<R, C, A0, A1, A2, A3>();
}

/// 5 args ---
///
template <typename R, typename A0, typename A1, typename A2, typename A3, typename A4> struct FreeFunctionProxy5
{
	typedef R (*FPtr)(A0, A1, A2, A3, A4);
	typedef Function<R (A0, A1, A2, A3, A4)> Func;

	template <FPtr fp>
	static Func bind()
	{
		return Func(&FreeFunctionProxy5::template wrapper<fp>, 0);
	}

private:
	template <FPtr fp>
	static R wrapper(const void*, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4)
	{
		return fp(a0, a1, a2, a3, a4);
	}
};

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3, typename A4> struct MemberFunctionProxy5
{
	typedef R (C::* const FPtr)(A0, A1, A2, A3, A4);
	typedef Function<R (A0, A1, A2, A3, A4)> Func;

	template <FPtr fp>
	static Func bind(C* ip)
	{
		return Func(&MemberFunctionProxy5::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4)
	{
		C* instance = const_cast<C*>(static_cast<const C*>(ip));
		return (instance->*fp)(a0, a1, a2, a3, a4);
	}
};

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3, typename A4> struct ConstMemberFunctionProxy5
{
	typedef R (C::* const FPtr)(A0, A1, A2, A3, A4) const;
	typedef Function<R (A0, A1, A2, A3, A4)> Func;

	template <FPtr fp>
	static Func bind(const C* ip)
	{
		return Func(&ConstMemberFunctionProxy5::template wrapper<fp>, ip);
	}

private:
	template <FPtr fp>
	static R wrapper(const void* ip, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4)
	{
		const C* instance = static_cast<const C*>(ip);
		return (instance->*fp)(a0, a1, a2, a3, a4);
	}
};

///
template <typename R, typename A0, typename A1, typename A2, typename A3, typename A4> FreeFunctionProxy5<R, A0, A1, A2, A3, A4> makeProxy(R (*fp)(A0, A1, A2, A3, A4))
{
	return FreeFunctionProxy5<R, A0, A1, A2, A3, A4>();
}

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3, typename A4> MemberFunctionProxy5<R, C, A0, A1, A2, A3, A4> makeProxy(R (C::* const fp)(A0, A1, A2, A3, A4))
{
	return MemberFunctionProxy5<R, C, A0, A1, A2, A3, A4>();
}

///
template <typename R, typename C, typename A0, typename A1, typename A2, typename A3, typename A4> ConstMemberFunctionProxy5<R, C, A0, A1, A2, A3, A4> makeProxy(R (C::* const fp)(A0, A1, A2, A3, A4) const)
{
	return ConstMemberFunctionProxy5<R, C, A0, A1, A2, A3, A4>();
}

///
template <typename R> class Function<R ()>
{
	typedef R (*StaticFuncPtr)(const void*);
	typedef const void* Function::*bool_type;

public:
	Function() : _func(0), _data(0) {}
	Function(StaticFuncPtr f, const void* d) : _func(f), _data(d) {}

	R operator () () const
	{
		return _func(_data);
	}

	operator bool_type() const
	{
		return 0 != _func ? &Function::_data : 0;
	}

	bool operator == (const Function& other) const
	{
		return _func == other._func  &&  _data == other._data;
	}

	bool operator != (const Function& other) const
	{
		return _func != other._func  ||  _data != other._data;
	}

	Function& operator = (const Function& rhs)
	{
		_func = rhs._func;
		_data = rhs._data;
		return *this;
	}

private:
	StaticFuncPtr	_func;
	const void*		_data;
};


///
template <typename R, typename A0> class Function<R (A0)>
{
	typedef R (*StaticFuncPtr)(const void*, A0);
	typedef const void* Function::*bool_type;

public:
	Function() : _func(0), _data(0) {}
	Function(StaticFuncPtr f, const void* d) : _func(f), _data(d) {}

	R operator () (A0 a0) const
	{
		return _func(_data, a0);
	}

	operator bool_type() const
	{
		return 0 != _func ? &Function::_data : 0;
	}

	bool operator == (const Function& other) const
	{
		return _func == other._func  &&  _data == other._data;
	}

	bool operator != (const Function& other) const
	{
		return _func != other._func  ||  _data != other._data;
	}

	Function& operator = (const Function& rhs)
	{
		_func = rhs._func;
		_data = rhs._data;
		return *this;
	}

private:
	StaticFuncPtr	_func;
	const void*		_data;
};


///
template <typename R, typename A0, typename A1> class Function<R (A0, A1)>
{
	typedef R (*StaticFuncPtr)(const void*, A0, A1);
	typedef const void* Function::*bool_type;

public:
	Function() : _func(0), _data(0) {}
	Function(StaticFuncPtr f, const void* d) : _func(f), _data(d) {}

	R operator () (A0 a0, A1 a1) const
	{
		return _func(_data, a0, a1);
	}

	operator bool_type() const
	{
		return 0 != _func ? &Function::_data : 0;
	}

	bool operator == (const Function& other) const
	{
		return _func == other._func  &&  _data == other._data;
	}

	bool operator != (const Function& other) const
	{
		return _func != other._func  ||  _data != other._data;
	}

	Function& operator = (const Function& rhs)
	{
		_func = rhs._func;
		_data = rhs._data;
		return *this;
	}

private:
	StaticFuncPtr	_func;
	const void*		_data;
};


///
template <typename R, typename A0, typename A1, typename A2> class Function<R (A0, A1, A2)>
{
	typedef R (*StaticFuncPtr)(const void*, A0, A1, A2);
	typedef const void* Function::*bool_type;

public:
	Function() : _func(0), _data(0) {}
	Function(StaticFuncPtr f, const void* d) : _func(f), _data(d) {}

	R operator () (A0 a0, A1 a1, A2 a2) const
	{
		return _func(_data, a0, a1, a2);
	}

	operator bool_type() const
	{
		return 0 != _func ? &Function::_data : 0;
	}

	bool operator == (const Function& other) const
	{
		return _func == other._func  &&  _data == other._data;
	}

	bool operator != (const Function& other) const
	{
		return _func != other._func  ||  _data != other._data;
	}

	Function& operator = (const Function& rhs)
	{
		_func = rhs._func;
		_data = rhs._data;
		return *this;
	}

private:
	StaticFuncPtr	_func;
	const void*		_data;
};


///
template <typename R, typename A0, typename A1, typename A2, typename A3> class Function<R (A0, A1, A2, A3)>
{
	typedef R (*StaticFuncPtr)(const void*, A0, A1, A2, A3);
	typedef const void* Function::*bool_type;

public:
	Function() : _func(0), _data(0) {}
	Function(StaticFuncPtr f, const void* d) : _func(f), _data(d) {}

	R operator () (A0 a0, A1 a1, A2 a2, A3 a3) const
	{
		return _func(_data, a0, a1, a2, a3);
	}

	operator bool_type() const
	{
		return 0 != _func ? &Function::_data : 0;
	}

	bool operator == (const Function& other) const
	{
		return _func == other._func  &&  _data == other._data;
	}

	bool operator != (const Function& other) const
	{
		return _func != other._func  ||  _data != other._data;
	}

	Function& operator = (const Function& rhs)
	{
		_func = rhs._func;
		_data = rhs._data;
		return *this;
	}

private:
	StaticFuncPtr	_func;
	const void*		_data;
};


///
template <typename R, typename A0, typename A1, typename A2, typename A3, typename A4> class Function<R (A0, A1, A2, A3, A4)>
{
	typedef R (*StaticFuncPtr)(const void*, A0, A1, A2, A3, A4);
	typedef const void* Function::*bool_type;

public:
	Function() : _func(0), _data(0) {}
	Function(StaticFuncPtr f, const void* d) : _func(f), _data(d) {}

	R operator () (A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const
	{
		return _func(_data, a0, a1, a2, a3, a4);
	}

	operator bool_type() const
	{
		return 0 != _func ? &Function::_data : 0;
	}

	bool operator == (const Function& other) const
	{
		return _func == other._func  &&  _data == other._data;
	}

	bool operator != (const Function& other) const
	{
		return _func != other._func  ||  _data != other._data;
	}

	Function& operator = (const Function& rhs)
	{
		_func = rhs._func;
		_data = rhs._data;
		return *this;
	}

private:
	StaticFuncPtr	_func;
	const void*		_data;
};

} // namespace pl

//
// End of file 'pulsar_function.h'
//